/*
 * Copyright (c) 2008, Solido Systems
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of Solido Systems nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package com.solidosystems.objectkitchen.net;

import java.io.*;
import java.net.*;
import java.util.*;
import com.solidosystems.objectkitchen.data.*;
import com.solidosystems.objectkitchen.storage.*;

import static com.solidosystems.objectkitchen.client.StorageConnector.*;

public class StorageThread implements Runnable{
	private BlockSet block;
	private Socket socket;
	private DataInputStream bufin;
	private DataOutputStream bufout;
	
	public StorageThread(BlockSet block,Socket socket){
		try{
			this.socket=socket;
			this.block=block;
			bufin=new DataInputStream(new BufferedInputStream(socket.getInputStream()));
			bufout=new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
			new Thread(this).start();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void handlePing() throws IOException{
		bufout.writeByte(OK);
		bufout.flush();
	}
	
	public void handleGetDoc() throws IOException{
		String id=bufin.readUTF();
		Document doc=block.getOrCreateDocument(id);
		if(doc!=null){
			bufout.writeByte(OK);
			doc.writeToStream(bufout);
		}else{
			bufout.writeByte(ERR);
		}
		bufout.flush();
	}
	
	public void handlePutDoc() throws IOException{
		Document doc=Document.readFromStream(bufin);
		if(doc!=null){
			block.putDocument(doc);
			bufout.writeByte(OK);
		}else{
			bufout.writeByte(ERR);
		}
		bufout.flush();
	}
	
	public void handleDelDoc() throws IOException{
		String id=bufin.readUTF();
		block.deleteDocument(id);
		bufout.writeByte(OK);
		bufout.flush();
	}
	
	public void handleGetAtt() throws IOException{
		String id=bufin.readUTF();
		String title=bufin.readUTF();
		byte[] data=block.getAttachment(id,title);
		if(data!=null){
			bufout.writeByte(OK);
			bufout.writeInt(data.length);
			bufout.write(data,0,data.length);
		}else{
			bufout.writeByte(ERR);
		}
		bufout.flush();
	}
	
	public void handlePutAtt() throws IOException{
		String id=bufin.readUTF();
		String title=bufin.readUTF();
		if(block.hasDocument(id)){
			bufout.writeByte(OK);
			bufout.flush();
			int size=bufin.readInt();
			byte[] buf=new byte[size];
			bufin.readFully(buf);
			block.putAttachment(id,title,buf);
			bufout.writeByte(OK);
		}else{
			bufout.writeByte(ERR);
		}
		bufout.flush();
	}
	
	public void handleDelAtt() throws IOException{
		String id=bufin.readUTF();
		String title=bufin.readUTF();
		if(block.hasDocument(id)){
			block.deleteAttachment(id,title);
			bufout.writeByte(OK);
		}else{
			bufout.writeByte(ERR);
		}
		bufout.flush();
	}
	
	public void run(){
		while(true){
			try{
				int cmd=bufin.readByte();
				switch(cmd){
					case QUIT: 	bufout.writeByte(OK);
								bufout.flush();
								bufout.close();
								bufin.close();
								socket.close();
								return;
					case PING: handlePing();
						break;
					case GET_DOC: handleGetDoc();
						break;
					case PUT_DOC: handlePutDoc();
						break;
					case DEL_DOC: handleDelDoc();
						break;
					case GET_ATT: handleGetAtt();
						break;
					case PUT_ATT: handlePutAtt();
						break;
					case DEL_ATT: handleDelAtt();
						break;
				}
			}catch(Exception e){
				e.printStackTrace();
				return;
			}
		}
	}
}